package jadex.examples.hunterprey.creature.preys.Njftprey;

import java.util.*;

import jadex.adapter.fipa.AgentDescription;
import jadex.adapter.fipa.SFipa;
import jadex.adapter.fipa.SearchConstraints;
import jadex.adapter.fipa.ServiceDescription;
import jadex.examples.hunterprey.*;
import jadex.runtime.*;
import jadex.util.SUtil;

/**
 *  Plan to move around in the environment and try to eat food.
 */
public class NjftpreyPlan extends Plan
{
	//-------- attributes --------

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/** Random number generator. */
	protected Random	rand;
	
	/**
	 * The shared Vision.
	 */
	protected NjftVision publicVision;
	protected Creature me;
	protected WorldObject[]	objects;
	
	//-------- constructors --------

	/**
	 *  Create a new plan.
	 */
	public NjftpreyPlan()
	{
		this.rand	= new Random(hashCode());
		publicVision = NjftVision.getInstance();
	}

	//-------- methods --------

	/**
	 *  The plan body.
	 */
	public void body()
	{
		waitForBeliefChange("vision");
	    //waitForCondition(getCondition("has_vision"));
		//int	dir	= 0;
		
		while(true)
		{
			me = ((Creature)getBeliefbase().getBelief("my_self").getFact());
			Vision vision = ((Vision)getBeliefbase().getBelief("vision").getFact());
			publicVision.addVision(vision);
			//TODO make up something clever about the moving hunters   ~niko
			
			
			objects	= vision.getObjects();
			me.sortByDistance(objects);
	    	String[] posdirs = me.getPossibleDirections(objects);

			// Find nearest interesting objects.
			int	distance	= Integer.MAX_VALUE;
			ArrayList	interesting	= new ArrayList();
			for(int i=0; i<objects.length; i++)
			{
				if(objects[i] instanceof Food)
				{
					int	dist	= me.getDistance(objects[i]);
					if(dist>distance)
						break;
					interesting.add(objects[i]);
					distance	= dist;
					
					Location foodloc = objects[i].getLocation();
					this.inform_Prey(foodloc);
				} else if((objects[i] instanceof Hunter)) {
					//when a hunter appears =)
				}
			}

			// Take appropriate action (move or eat).
			if(interesting.size()>0 && Math.random()>0.1)
			{
				WorldObject	obj	= (WorldObject)interesting.get(rand.nextInt(interesting.size()));
				// Move towards nearest object.
				String[] dirs	= me.getDirections(obj);
	        	String[] posmoves = (String[])SUtil.cutArrays(dirs, posdirs);

				if(me.getDistance(obj)==0)
				{
					eat(obj);
				}
				else if(posmoves.length>0)
				{
					// Move towards object.
					move(posmoves[rand.nextInt(posmoves.length)]);
				}
				else
				{
					// Move randomly.
					move(posdirs[rand.nextInt(posdirs.length)]);
				}
			}
			else if(getBeliefbase().getBelief("food_location").getFact() != null) {
				Location foodloc = (Location)getBeliefbase().getBelief("food_location").getFact();
				moveToFood(foodloc);
			}
			else
			{
				// Move randomly.
				move(posdirs[rand.nextInt(posdirs.length)]);
			}
		}
	}

	private void inform_Prey(Location foodloc) {
		//SEND
		ServiceDescription sd = new ServiceDescription("service_preyinform", null, null);
		AgentDescription ad = new AgentDescription();
		ad.addService(sd);
		
		SearchConstraints constraints = new SearchConstraints();
		constraints.setMaxResults(-1);
		
		IGoal ft = createGoal("df_search");
		ft.getParameter("description").setValue(ad);
//		ft.getParameter("constraints").setValue(constraints);
		
		dispatchSubgoalAndWait(ft);
		
		AgentDescription[] sentries = (AgentDescription[])ft.getParameterSet("result").getValues();
		
		if(sentries.length > 0) {
			IMessageEvent mevent = createMessageEvent("foodinform");
			for (int i = 0; i < sentries.length; i++) {
//				System.out.println("Receiver: " + sentries.length + " Name: " + sentries[i].getName());
				mevent.getParameterSet(SFipa.RECEIVERS).addValue(sentries[i].getName());
			}
			mevent.setContent(foodloc.getX() + "," + foodloc.getY());
			sendMessage(mevent);
		}
	}
	/**
	 * Move towards food-pool
	 */
	protected void moveToFood(Location foodloc) {
		String[] dirs = me.getDirections(me.getLocation(), foodloc);
	    String[] posdirs = me.getPossibleDirections(objects);
        String[] posmoves = (String[])SUtil.cutArrays(dirs, posdirs);
	    
        boolean success = false;
		// Try different possible directions towards target.
        for(int i=0; i<posmoves.length && !success; i++)
        {
	        IGoal move = createGoal("move");
	        move.getParameter("direction").setValue(posmoves[i]);
	        try
			{
	        	dispatchSubgoalAndWait(move);
	            me = (Creature)getBeliefbase().getBelief("my_self").getFact();
	            success = true;
			}
	        catch(GoalFailureException gfe){}
	    }
        getBeliefbase().getBelief("food_location").setFact(null);
	    if(!success)
	    {
//			throw new PlanFailureException();
	        System.out.println("Cannot reach location :-(");
	    }
	}
	
	/**
	 *  Move towards a direction.
	 */
	protected void move(String direction)
	{
		try
		{
//			System.out.println(getAgentName()+" wants to move: "+direction);
			IGoal move = createGoal("move");
			move.getParameter("direction").setValue(direction);
			dispatchSubgoalAndWait(move);
		}
		catch(GoalFailureException e)
		{
			getLogger().warning("Move goal failed");
		}
	}

	/**
	 *  Eat an object.
	 */
	protected void eat(WorldObject object)
	{
		try
		{
			IGoal eat = createGoal("eat");
			eat.getParameter("object").setValue(object);
			dispatchSubgoalAndWait(eat);
			publicVision.food.remove(object);
		}
		catch(GoalFailureException e)
		{
			getLogger().warning("Move goal failed");
		}
	}
}


